-
Notifications
You must be signed in to change notification settings - Fork 18
[WIP] Implement VOCS interface #281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
* Internals maintain Optimas data structures * Update sampling tests
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
In updating Optimas generators for the standard, how do we deal with these extra fields in lower_bound: float
upper_bound: float
is_fidelity: Optional[bool] = False
fidelity_target_value: Optional[float] = None
default_value: Optional[float] = None
_is_fixed: bool = PrivateAttr(False) re: https://github.com/optimas-org/optimas/blob/main/optimas/core/parameter.py#L79 In the standard, variables have https://github.com/campa-consortium/generator_standard/blob/main/generator_standard/vocs.py#L16 Do we need
e.g. var1 = VaryingParameter("x0", -50.0, 5.0)
var2 = VaryingParameter("x1", -5.0, 15.0)
# Start with a fixed value of x0.
var1.fix_value(-10.0)
...
exploration.run(n_evals=5)
var1.free_value()
gen.update_parameter(var1)
exploration.run(n_evals=5) could be instructed directly to generator instead - for supporting gens. e.g. gen.fix_var('x0', -10.0) Alternatively, we could add fields to the standard, or create subclasses to Currently, I have used the following generator functions (shown with example calls) to set the Optimas internals for these, without adding to or subclassing
These are used in |
Observables (analysed parameters) in Optimas can specify a type, but this isn’t supported in the standard interface. A type is necessary for constructing a NumPy structured array (for libEnsemble). For example, in this test, the type must be a string. https://github.com/optimas-org/optimas/blob/main/tests/test_env_script.py#L27 In test_template_evaluator.py and test_function_evaluator.py it stores an array and a plot object. I have suggested we allow specifying a type for observables and constants in the standard. The standard does not support arrays generally, but I have made it possible to specify a string or a tuple for observable type, which means numpy arrays can be used. e.g. def test_template_evaluator():
# Define variables and objectives.
vocs = VOCS(
variables={"x0": [-50.0, 5.0], "x1": [-5.0, 15.0]},
objectives={"f": "MAXIMIZE"},
observables={
"p0": (float, (2, 4)),
"p1": "O",
"fig": "O",
},
)
# Define variables and objectives.
gen = RandomSamplingGenerator(vocs=vocs) |
exploration_diagnostics: exploration_diagnostics.py: test_exploration_diagnostics.py: # Check that all possible objective inputs give the same result.
_, trace1 = diags.get_objective_trace()
_, trace2 = diags.get_objective_trace("f1")
# _, trace3 = diags.get_objective_trace(obj) # Can be removed
np.testing.assert_array_equal(trace1, trace2)
# np.testing.assert_array_equal(trace1, trace3) |
Note that |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
Small point. In outcome_constraints=["p1 <= 30"], becomes: constraints={"p1": ["LESS_THAN", 30.0]}, |
What do we do for test test_ax_single_fidelity_int. Do we need to support this? var1 = VaryingParameter("x0", -50.0, 5.0, dtype=int)
var2 = VaryingParameter("x1", -5.0, 15.0) In vocs this becomes: vocs = VOCS(
variables={"x0": set(range(-50, 6)), "x1": [-5.0, 15.0]},
objectives={"f": "MAXIMIZE"},
) I don't see anything to deal with discrete vars in Optimas, so I have converted to integer type when its a range but that seems hacky. To support this elegantly, we could bring back |
varying_parameters=[var1, var2], objectives=[obj] | ||
# TODO: Suggest supporting IntegerVariables in vocs | ||
vocs = VOCS( | ||
variables={"x0": set(range(-50, 6)), "x1": [-5.0, 15.0]}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a need for a continuous range of integers?
_, trace1 = diags.get_objective_trace() | ||
_, trace2 = diags.get_objective_trace("f1") | ||
_, trace3 = diags.get_objective_trace(obj) | ||
# _, trace3 = diags.get_objective_trace(obj) # Can be removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with removing this line (and the associated np.testing.assert_array_equal
below)
if not self._vocs.constraints: | ||
return None | ||
constraints = [] | ||
for const_name, const_spec in self._vocs.constraints.items(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we raise an exception for now, saying that constraints are not supported in optimas
generators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have tests with constraints such as
optimas/tests/test_ax_generators.py
Line 158 in b760144
constraints={"p1": ["LESS_THAN", 30.0]}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, I see now, it does nothing with it internally, I can add, but what do we do with these tests. Currently, being ignored.
name=var_name, | ||
lower_bound=sorted_values[0], | ||
upper_bound=sorted_values[-1], | ||
dtype=int, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this work for https://github.com/optimas-org/optimas/pull/281/files#diff-54d05e7e049beb11035069e9030950c2b1080b97631d4fa5d984eb8bfe347638R541 where the discrete variables are string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conversion of strings was added to multitask to deal with that case. So currently I think base generator class would not work with strings. Looking at that, I think we could move that conversion to the base class so it supports strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String type variables convert to Optimas TrialParameters because, VaryingParameters require upper/lower bounds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved that conversion to the generator base class now. That function can be used by any Optimas generator that requires discrete variables.
fidelity_parameter="resolution", | ||
fidelity_target_value=4.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these variables fit the standard of VOCS
?
My impression is that it would be better to pass them to AxMultiFidelityGenerator
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, I will be running, testing the full examples on Perlmutter soon.
# SH We can use a discrete var here in vocs (converted for now to trial parameters) | ||
# But unlike varying parameters the name refers to a fixed generator concept. | ||
for trial_param in self._custom_trial_parameters: | ||
if trial_param.name == "trial_type": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit confused ; does this if condition ever become true?
Given that we have:
custom_trial_parameters = [
TrialParameter("arm_name", "ax_arm_name", dtype="U32"),
TrialParameter("ax_trial_id", "ax_trial_index", dtype=int),
]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually: looking at the rest of the code in this PR, it seems that this would be a case where we use set_fidelity_param
on the generator, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's created in the generator. When a discrete variable type is given in vocs
. Optimas internally uses trial_parameters. So trial_type is a discrete variable.
optimas/optimas/generators/base.py
Line 204 in fa74f3f
def _convert_vocs_discrete_variables_to_trial_parameters( |
In the multifidelity generator (resolution), its using a Continuous variable, which is basically the same as it was before in Optimas (using a VaryingParameter), but it may be fidelity is better expressed as discrete always?
The arm_name and ax_trial_id are created in the generator as these are not vocs
parameters. They are fixed generator fields.
This implements Step 3 in #269
For first pass, keep internals the same and implement interface:
Implementation:
validate_vocs
functionsvalidate_vocs
functions and incorporate previous check functions.validate_vocs
exceptions_id
and internal mapping - undoneChecks:
Reviewer checks:
validate_vocs
functions